package cn.tedu.charging.cost.dao.repository.impl;

import cn.tedu.charging.common.constant.CacheKeyConst;
import cn.tedu.charging.cost.dao.mapper.CostRuleMapper;
import cn.tedu.charging.cost.dao.repository.CostRuleRepository;
import cn.tedu.charging.cost.pojo.po.ChargingCostRulePO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

@Repository
@Slf4j
public class CostRuleRepositoryImpl implements CostRuleRepository {
    @Autowired
    private CostRuleMapper costRuleMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public ChargingCostRulePO getCostRule(Integer stationId, Integer hour) {
        /**
         * name   start  end  power_fee gun_type station_id
         * 尖上午   08     12     1.50   快      5     #场站id是5,时间段[08,12) 按照1.5元/度
         * 尖下午   14     18     1.50   快      5     #场站id是5,时间段[14,18) 按照1.5元/度
         * 全天峰   18     24     1.40   快      5     #场站id是5,时间段[18,24) 按照1.4元/度
         * 全天平   12     14     1.30   快      5     #场站id是5,时间段[12,14) 按照1.3元/度
         * 全天谷   00     08     1.00   快      5     #场站id是5,时间段[00,08) 按照1.0元/度
         * 全天时   00     24     1.00   快      6     #场站id是6,时间段[00,24) 按照1.0元/度
         */
        //方案1:直接使用sql的where条件 利用场站id和时间小时数 拼接sql
        //select * from charging_cost_rule where station_id=#{stationId}
        // and start_time<=#{hour} and end_time>#{hour}
        /*QueryWrapper queryWrapper=new QueryWrapper();
        queryWrapper.eq("station_id",stationId);
        queryWrapper.le("start_time",hour);
        queryWrapper.gt("end_time",hour);
        //当前条件,我们查询到了唯一一个计价规则
        ChargingCostRulePO costRule = costRuleMapper.selectOne(queryWrapper);*/
        //方案2: 利用stationId 和枪类型,运营商因素都考虑到 查询规则,唯独没有时间条件 查询的是列表
        /*QueryWrapper<ChargingCostRulePO> queryWrapper=new QueryWrapper();
        queryWrapper.eq("station_id",stationId);
        List<ChargingCostRulePO> rules = costRuleMapper.selectList(queryWrapper);
        //普通循环遍历
        ChargingCostRulePO rule=null;
        List<ChargingCostRulePO> rulesFiltered=rules.stream().filter(po->{
            Integer startTime = po.getStartTime();
            Integer endTime = po.getEndTime();
            return startTime<=hour&&endTime>hour;
        }).collect(Collectors.toList());
        if (rulesFiltered!=null&&rulesFiltered.size()>0){
            rule=rulesFiltered.get(0);
        }*/
        /*for (ChargingCostRulePO chargingCostRulePO : rules) {
            //判断哪个时间条件满足
            Integer startTime = chargingCostRulePO.getStartTime();
            Integer endTime = chargingCostRulePO.getEndTime();
            //如果当前hour是满足时间条件 给rule赋值
            if (startTime<=hour&&endTime>hour){
                rule=chargingCostRulePO;
                break;
            }
        }*/
        //方案3:利用stationId做缓存 存储数据格式list 完成旁路缓存逻辑
        //1.准备一个key值 用来绑定场站id 读写list规则列表
        String stationRulesKey="charging:station:rules:"+stationId;
        //读取缓存 lrange key 0 -1 读取list所有元素
        ListOperations<String,ChargingCostRulePO> listOps = redisTemplate.opsForList();
        List<ChargingCostRulePO> rulesCache = listOps.range(stationRulesKey, 0, -1);
        //判断命中结果
        if (rulesCache==null||rulesCache.size()==0){
            //2.没命中,读取数据库
            QueryWrapper<ChargingCostRulePO> queryWrapper=new QueryWrapper();
            queryWrapper.eq("station_id",stationId);
            List<ChargingCostRulePO> rules = costRuleMapper.selectList(queryWrapper);
            //3.放到缓存 lpush key rule1 rule2....回填
            listOps.leftPushAll(stationRulesKey,rules);
            rulesCache=rules;
        }
        //4 从列表中筛选
        List<ChargingCostRulePO> rulesFiltered=rulesCache.stream().filter(po->{
            return po.getStartTime()<=hour&&po.getEndTime()>hour;
        }).collect(Collectors.toList());
        ChargingCostRulePO rule=null;
        if (rulesFiltered!=null&&rulesFiltered.size()>0){
            rule=rulesFiltered.get(0);
        }
        return rule;
    }

    //set key value GET
    @Override
    public BigDecimal getAndSetTotalCapaicity(String orderNo, Double totalCapacity) {
        //1.准备一个key值 存储当前订单的总度数
        String orderTotalCapacityKey="charging:total:capacity:"+orderNo;
        //2.set key totalCapacity GET(SET 属于String数据结构的)
        ValueOperations<String,Double> valueOps = redisTemplate.opsForValue();
        Double lastTotalCapacity = valueOps.getAndSet(orderTotalCapacityKey, totalCapacity);
        //3.返回一个bigDecimal的数据
        if (lastTotalCapacity!=null){
            return new BigDecimal(lastTotalCapacity+"");
        }else{
            return null;
        }
    }


    //incrby key number
    //incrby只能操作整数 redisTemplate的客户端 可以帮助我们扩展incrby
    @Override
    public BigDecimal accumulateTotalCost(String orderNo, BigDecimal currentCost) {
        //要使用本次计算的金额 和上次的总金额 做累加
        //1.准备一个存储上次总金额的key
        String orderTotalCostKey=CacheKeyConst.CHARGING_TOTAL_COST_PREFIX+orderNo;
        //2.直接调用incrby key currentCost
        ValueOperations<String,Double> valueOps = redisTemplate.opsForValue();
        Double currentTotalCost = valueOps.increment(orderTotalCostKey, currentCost.doubleValue());
        return new BigDecimal(currentTotalCost+"");
    }
}
